using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Xml.Serialization;
using Microsoft.SharePoint.WebControls;

namespace OrbitOne.SharePoint.Provision.WebParts
{
    [Guid("0e62e5a7-83aa-4b66-80cc-0f7b8ae21dfa"),
    ToolboxData("<{0}:CreateUserWebPart runat=server></{0}:CreateUserWebPart>"),
    XmlRoot(Namespace = "OrbitOne.Provision.WebParts")]
    public class CreateUserWebPart : GeneralWebPart
    {
       private static readonly string Email_Validation_Expression =
                @"^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?`\{\|\}~]+@(?:(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!\.)){0,61}[a-zA-Z0-9]?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!$)){0,60}[a-zA-Z0-9])|(?:\[(?:(?:[01]?\d{1,2}|20-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$";
        // Declare variables for HtmlControls user interface elements.
        HtmlButton _createUser;
        HtmlInputText _userFirstName;
        HtmlInputText _userLastName;
        HtmlInputText _userLogin;
        HtmlInputCheckBox _generatePassword;
        HtmlInputPassword _password;
        HtmlInputPassword _passwordVerify;
        HtmlInputText _passwordQuestion;
        HtmlInputText _passwordAnswer;
        HtmlInputText _email;
        HtmlTextArea _status;
        HtmlInputCheckBox _sendNotificationEmail;
       
        bool _showPassQA = true;
               
       
    

        protected override void OnLoad(EventArgs e)
        {
            // Get the URL of the current site
            _siteUrl = SPControl.GetContextWeb(Context).Url.ToString();

            // Determine which type of provider is being used: AD or SQL (either are supported)
            DetermineProviderType();


            // Is it required to have a question and answer?
            _showPassQA = Membership.Provider.RequiresQuestionAndAnswer;

            base.OnLoad(e);
        }


        protected override void OnPreRender(EventArgs e)
        {
            // If this web part is being drawn and no failure has occured,
            //  the make sure textbox values are cleared
            if (!_failure)
            {
                // Clear the fields
                _userFirstName.Value = "";
                _userLastName.Value = "";
                _userLogin.Value = "";
                _password.Value = "";
                _passwordQuestion.Value = "";
                _passwordAnswer.Value = "";
                _email.Value = "";
                
                 
               
                    _generatePassword.Checked = false;
               
            }

            base.OnPreRender(e);
        }

        protected override void CreateChildControls()
        {
            _userFirstName = new HtmlInputText();
            _userLastName = new HtmlInputText();
            
            _userLogin = new HtmlInputText();
            _generatePassword = new HtmlInputCheckBox();
            _password = new HtmlInputPassword();
            _passwordVerify = new HtmlInputPassword();
            _passwordQuestion = new HtmlInputText();
            _passwordAnswer = new HtmlInputText();
            _email = new HtmlInputText();
            _createUser = new HtmlButton();
            _status = new HtmlTextArea();
            _sendNotificationEmail = new HtmlInputCheckBox();
            _sendNotificationEmail.Checked = true;
            // Make these fields a bit longer
            _passwordQuestion.Size = 50;
            _passwordAnswer.Size = 50;

            // Button text
            _createUser.InnerText = "Create User";

            // Add an event handler when the button is clicked
            _createUser.ServerClick += new EventHandler(_createUser_ServerClick);

            // Add a client-side event handler on the Generate Password checkbox
            
                _generatePassword.Attributes.Add("id", "generate_password_checkbox");
                _generatePassword.Attributes.Add("onClick", "javascript:togglePasswordInput();");
          
            _sendNotificationEmail.Attributes.Add("id","send_notification_email_checkbox");
            _sendNotificationEmail.Attributes.Add("onClick", "javascript:toggleGeneratePasswordInput();");



            // Add the controls to the web part
            Controls.Add(_userFirstName);
            Controls.Add(_userLastName);
            Controls.Add(_generatePassword);
            Controls.Add(_userLogin);
            Controls.Add(_password);
            Controls.Add(_passwordVerify);
            Controls.Add(_passwordQuestion);
            Controls.Add(_passwordAnswer);
            Controls.Add(_email);
            Controls.Add(_createUser);
            Controls.Add(_status);
            Controls.Add(_sendNotificationEmail);
        }


        /// <summary>
        /// User clicks on the button to create the user
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Class containing event data</param>
        public void _createUser_ServerClick(object sender, EventArgs e)
        {
            string errorMessage;
            if (!this.ValidateInput(out errorMessage))
            {
                _failure = true;
                _status.Value = "Invalid or empty input: "+errorMessage;
                return;
            }

            string fullName;
            string newPassword;
            string currentUserFullName;

            // The current user's full name is specified in the SharePoint display name value
            currentUserFullName = SharePointProvisioning.GetCurrentDisplayName();

            try
            {
                // Is the Generate Password checkbox checked?
                if (_generatePassword.Checked)
                {
                    // Generate a new password based on the criteria specified in the web.config file
                    if (Membership.Provider.MinRequiredPasswordLength==0)
                    {
                        newPassword =
                            Membership.GeneratePassword(Constants.DEFAULT_PASSWORD_LENGTH,
                                                        Constants.DEFUALT_NONE_ALPHANUMERIC_COUNT);
                    }
                    else  if (_providerType == "WindowsIntergrated")
                    {
                        newPassword = GeneratePassword();
                    }
                    else 
                    {
                        newPassword =
                        Membership.GeneratePassword(Membership.Provider.MinRequiredPasswordLength,
                                                    Membership.Provider.MinRequiredNonAlphanumericCharacters);
                    }
                }
                
                else
                {
                    // Make sure the passwords match and conform to policy guidlines specified in the provider
                    CheckPassword(_password.Value.ToString(), _passwordVerify.Value.ToString());

                    // Use the password value specified in the form
                    newPassword = _password.Value.ToString();
                }

                // Get the user's full name
                fullName = _userFirstName.Value.ToString() + " " + _userLastName.Value.ToString();


                if (_providerType == "SQL")
                {
                    // Create the user in SQL
                    SQLProvisioning.CreateUser(_userLogin.Value.ToString(), newPassword, _email.Value.ToString(),
                                               _passwordQuestion.Value.ToString(), _passwordAnswer.Value.ToString());
                    AddUserToSharePoint(fullName, newPassword, currentUserFullName,false);
                }
                else if (_providerType == "AD")
                {

                    CreateADUser(newPassword);
                    AddUserToSharePoint(fullName, newPassword, currentUserFullName,false);
                }
                else if (_providerType == "WindowsIntergrated")
                {
                   
                    CreateADUser(newPassword); 
                    AddUserToSharePoint(fullName, newPassword, currentUserFullName,true);
                }
                else
                {
                    // Unknown provider type - we can not create this user
                    throw new Exception(
                        "The user could not be created.  The authentication provider for this site could not be found.  Please contact your administrator for assistance.");
                }




                _status.Value = "User creation of " + fullName + " successfully completed. The user has been granted read permissions to this site.";
                _failure = false;
            }
            catch (Exception ex)
            {
               
                if (ex.Data.Contains("MailSendingFailedMessage"))
                {
                    _status.Value =
                        
                            "User was created successfully and has been granted read permissions to this site. But sending notification email to user failed: " + ex.Message;  
                }
                    _status.Value = ex.Message;
                _failure = true;
            }
        }
        private bool ValidateInput(out string errorMessage)
        {
            
            bool result = true;
            StringBuilder messageBuilder = new StringBuilder();
            if (string.IsNullOrEmpty(this._userFirstName.Value))
            {
                result = false;
                messageBuilder.Append("First Name, ");
            }
            if (string.IsNullOrEmpty(this._userLastName.Value))
            {
                result = false;
                messageBuilder.Append("Last Name, ");
            }
            if (string.IsNullOrEmpty(this._userLogin.Value))
            {
                result = false;
                messageBuilder.Append("User Login, ");
            }
            if (string.IsNullOrEmpty(this._email.Value))
            {
                result = false;
                messageBuilder.Append("Email Address, ");
            }
            else if (!Regex.IsMatch(this._email.Value, Email_Validation_Expression))
            {
                result = false;
                messageBuilder.Append("Email Address, ");
            }
            if(!_generatePassword.Checked&&string.IsNullOrEmpty(_password.Value))
            {
                result = false;
                messageBuilder.Append("Password, ");
            }

            if (!_generatePassword.Checked && string.IsNullOrEmpty(_passwordVerify.Value))
            {
                result = false;
                messageBuilder.Append("Verify Password, ");
            }


            errorMessage = messageBuilder.ToString().TrimEnd(", ".ToCharArray());
            return result;
        }
        private void AddUserToSharePoint(string fullName, string newPassword, string currentUserFullName,bool isWindowsAuthentication)
        {
            // Add the user to this site
            try
            {
                SharePointProvisioning.hstAddUsertoSite(_siteUrl,
                                                        _providerName + (isWindowsAuthentication ? string.Empty : ":") +
                                                        _userLogin.Value.ToString(),
                                                        fullName, _email.Value.ToString());
            }
            catch(Exception e)
            {
                DeleteAdUserOnError(_userLogin.Value.ToString());
                throw  e;
            }
            // Send an email to the user
            if(this._sendNotificationEmail.Checked)
            {

                SharePointProvisioning.hstSendEmail(fullName,currentUserFullName, _siteUrl, _userLogin.Value.ToString(),
                                                _email.Value.ToString(), newPassword, 1);
            }
        }
        private void DeleteAdUserOnError(string userLogin)
        {
            using (ElevationManager evelate = new ElevationManager())
            {
              
                ADProvisioning.DeleteUser(userLogin, SiteCollectionLADPConnectionString);

            }
        }
        private void CreateADUser(string newPassword)
        {
            // Impersonate the user specified in the web.config file who has permissions to complete these tasks
            using (ElevationManager evelate = new ElevationManager())
            {
                string ouName = GetGroupName();
                // Create the user in Active Directory
                ADProvisioning.CreateUser(_userFirstName.Value.ToString(), _userLastName.Value.ToString(),
                                          _userLogin.Value.ToString(), newPassword, _email.Value.ToString(),
                                          ouName,SiteCollectionLADPConnectionString);

                // Add the user to the corresponding "users" group of that OU - should be "<OU Name> Users"
                if (!ADProvisioning.IsGroupExist(ouName + " Users",SiteCollectionLADPConnectionString))
                {
                    ADProvisioning.CreateGroup(ouName + " Users",SiteCollectionOUName, SiteCollectionLADPConnectionString);
                }
                 ADProvisioning.AddUserToGroup(_userLogin.Value.ToString(), ouName + " Users",SiteCollectionLADPConnectionString);
            }
        }

        /// <summary>
        /// Build the Web Part user interface
        /// </summary>
        /// <param name="output">The HtmlTextWriter to render the output</param>
        private void BuildWSSUI(HtmlTextWriter output)
        {
            string messageColor;

            // Write any error or status messages
            if (_failure)
            {
                messageColor = "Red";
            }
            else
            {
                messageColor = "Green";
            }

            BuildStatus(_status.Value.ToString(), messageColor, output);

            // Start the table
            output.Write("<TABLE border='0' width='100%' cellspacing='0' cellpadding='0'>");

            // Build a row for each control
            
                BuildRow("First Name", "Enter the first name of the user to create.", _userFirstName, output, true);
                LineBreak("EndFirstName", output);
                BuildRow("Last Name", "Enter the last name of the user to create.", _userLastName, output, true);
                LineBreak("EndLastName", output);
           
            BuildRow("User Login", "Enter the login name the user will type when logging into the site.", _userLogin, output, true);
            LineBreak("EndLogin", output);
            BuildRow("Email Address", "Enter the email address for the new user.", _email, output, true);
            LineBreak("EndEmail", output);
            BuildRow("Generate Password", "Automatically generate a random password.", _generatePassword, output, _sendNotificationEmail.Checked);
            LineBreak("EndGeneratePassword", output);

            BuildRow("Password", "Enter a password for this new user.", _password, output, ShowPasswordInputControl());
            LineBreak("EndPassword", output);
            BuildRow("Verify Password", "Confirm the password for this new user.", _passwordVerify, output, ShowPasswordInputControl());
            LineBreak("EndVerifyPassword", output);
          
            if(_showPassQA && (_providerType == "SQL"))
            {
                BuildRow("Password Question", "Type a question that the user must answer to change his or her password.", _passwordQuestion, output, true);
                LineBreak("EndPassQuestion", output);
                BuildRow("Password Answer", "Type the answer to the previous question the user must answer to change his or her password.", _passwordAnswer, output, true);
                LineBreak("EndPassAnswer", output);
            }
            BuildRow("Send Invitation email to the user", "Send an email to the user that includes the username, password and a link to this site.", _sendNotificationEmail, output, true);
            LineBreak("EndNotificationEmail", output);
            // Draw the buttons
            BuildButton(_createUser, output);
            LineBreak("EndCreateButton", output, 2);

            // End the table
            output.Write("</TABLE>");

            // Add client-side script to show or hide the password fields
            StringBuilder displayScript = new StringBuilder();
            displayScript.Append("<script>");
            displayScript.Append("function togglePasswordInput(){");
            displayScript.Append("var myCheckbox = document.getElementById('generate_password_checkbox');");
            displayScript.Append("if(myCheckbox.checked == true) {");
            displayScript.Append("Password_row_main.style.display = 'none';");
            displayScript.Append("VerifyPassword_row_main.style.display = 'none';");
            displayScript.Append("}");
            displayScript.Append("else{");
            displayScript.Append("Password_row_main.style.display = '';");
            displayScript.Append("VerifyPassword_row_main.style.display = '';");
            displayScript.Append("}");
            displayScript.Append("}");


            displayScript.Append("function toggleGeneratePasswordInput(){");
            displayScript.Append("var myCheckbox = document.getElementById('send_notification_email_checkbox');");
            displayScript.Append("if(myCheckbox.checked == false) {");
            displayScript.Append("GeneratePassword_row_main.style.display = 'none';");
            displayScript.Append("Password_row_main.style.display = '';");
            displayScript.Append("VerifyPassword_row_main.style.display = '';");
            displayScript.Append("}");
            displayScript.Append("else{");
            displayScript.Append("GeneratePassword_row_main.style.display = '';");
            displayScript.Append("document.getElementById('generate_password_checkbox').checked = false;");
            displayScript.Append("Password_row_main.style.display = '';");
            displayScript.Append("VerifyPassword_row_main.style.display = '';");
            displayScript.Append("}");
            displayScript.Append("}");











            displayScript.Append("</script>");

            output.Write(displayScript.ToString());

        }
        
        private bool ShowPasswordInputControl()
        {
            if(!_sendNotificationEmail.Checked)
                return true;
            else
            {
                if(_generatePassword.Checked)
                    return false;
                else
                    return true;
            }
        }
        public override void RenderControl(HtmlTextWriter writer)
        {
            // Build the full user interface
            BuildWSSUI(writer);
        }

        
        

    }
}
